package cc.unitmesh.devins.ui.compose.agent

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Surface
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.Icon
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import cc.unitmesh.agent.render.TimelineItem
import cc.unitmesh.devins.llm.Message
import cc.unitmesh.devins.llm.MessageRole
import cc.unitmesh.devins.ui.compose.icons.AutoDevComposeIcons
import cc.unitmesh.devins.ui.compose.sketch.SketchRenderer
import cc.unitmesh.devins.ui.compose.sketch.getUtf8FontFamily
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

@Composable
fun AgentMessageList(
    renderer: ComposeRenderer,
    modifier: Modifier = Modifier,
    onOpenFileViewer: ((String) -> Unit)? = null
) {
    val listState = rememberLazyListState()
    val coroutineScope = rememberCoroutineScope()

    // Track if user manually scrolled away from bottom
    var userScrolledAway by remember { mutableStateOf(false) }

    // Track content updates from SketchRenderer for streaming content
    var streamingBlockCount by remember { mutableIntStateOf(0) }

    // Function to scroll to bottom
    fun scrollToBottomIfNeeded() {
        if (!userScrolledAway) {
            coroutineScope.launch {
                // Delay to ensure layout is complete before scrolling
                delay(50)
                val lastIndex = maxOf(0, listState.layoutInfo.totalItemsCount - 1)
                listState.scrollToItem(lastIndex)
            }
        }
    }

    // Monitor scroll state to detect user scrolling away
    LaunchedEffect(listState.isScrollInProgress) {
        if (listState.isScrollInProgress) {
            val lastVisibleIndex = listState.layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0
            val totalItems = listState.layoutInfo.totalItemsCount
            // If user scrolled to a position not near the bottom, they want to view history
            userScrolledAway = lastVisibleIndex < totalItems - 2
        }
    }

    // Scroll when timeline changes (new messages, tool calls, etc.)
    LaunchedEffect(renderer.timeline.size) {
        if (renderer.timeline.isNotEmpty()) {
            userScrolledAway = false
            coroutineScope.launch {
                delay(50)
                listState.animateScrollToItem(
                    index = maxOf(0, listState.layoutInfo.totalItemsCount - 1)
                )
            }
        }
    }

    // Scroll when streaming content changes
    LaunchedEffect(renderer.currentStreamingOutput) {
        if (renderer.currentStreamingOutput.isNotEmpty()) {
            // Calculate content signature based on line count and character chunks
            val lineCount = renderer.currentStreamingOutput.count { it == '\n' }
            val chunkIndex = renderer.currentStreamingOutput.length / 100
            val contentSignature = lineCount + chunkIndex

            // Delay to ensure Markdown layout is complete
            delay(100)
            scrollToBottomIfNeeded()
        }
    }

    // Scroll when SketchRenderer reports new blocks rendered
    LaunchedEffect(streamingBlockCount) {
        if (streamingBlockCount > 0) {
            delay(50)
            scrollToBottomIfNeeded()
        }
    }

    // Reset user scroll state when streaming starts
    LaunchedEffect(renderer.isProcessing) {
        if (renderer.isProcessing) {
            userScrolledAway = false
        }
    }

    LazyColumn(
        state = listState,
        modifier =
            modifier
                .fillMaxSize()
                .background(MaterialTheme.colorScheme.surface),
        contentPadding = PaddingValues(horizontal = 8.dp, vertical = 8.dp),
        verticalArrangement = Arrangement.spacedBy(6.dp)
    ) {
        items(
            items = renderer.timeline,
            key = { "${it.timestamp}_${it.hashCode()}" }
        ) { timelineItem ->
            RenderMessageItem(
                timelineItem = timelineItem,
                onOpenFileViewer = onOpenFileViewer,
                renderer = renderer,
                onExpand = {
                    coroutineScope.launch {
                        // Scroll to the bottom when an item expands
                        delay(50)
                        val totalItems = listState.layoutInfo.totalItemsCount
                        if (totalItems > 0) {
                            listState.animateScrollToItem(totalItems - 1)
                        }
                    }
                }
            )
        }

        if (renderer.currentStreamingOutput.isNotEmpty()) {
            item(key = "streaming") {
                StreamingMessageItem(
                    content = renderer.currentStreamingOutput,
                    onContentUpdate = { blockCount ->
                        // When SketchRenderer renders new blocks, trigger scroll
                        streamingBlockCount = blockCount
                    }
                )
            }
        }

        renderer.currentToolCall?.let { toolCall ->
            item(key = "current_tool_call") {
                CurrentToolCallItem(toolCall = toolCall)
            }
        }
    }
}

@Composable
fun RenderMessageItem(
    timelineItem: TimelineItem,
    onOpenFileViewer: ((String) -> Unit)?,
    renderer: ComposeRenderer,
    onExpand: () -> Unit = {}
) {
    when (timelineItem) {
        is TimelineItem.MessageItem -> {
            val msg = timelineItem.message ?: Message(
                role = timelineItem.role,
                content = timelineItem.content,
                timestamp = timelineItem.timestamp
            )
            MessageItem(
                message = msg,
                tokenInfo = timelineItem.tokenInfo
            )
        }

        is TimelineItem.ToolCallItem -> {
            ToolItem(
                toolName = timelineItem.toolName,
                details = timelineItem.params,
                fullParams = timelineItem.fullParams,
                filePath = timelineItem.filePath,
                toolType = timelineItem.toolType,
                success = timelineItem.success,
                summary = timelineItem.summary,
                output = timelineItem.output,
                fullOutput = timelineItem.fullOutput,
                executionTimeMs = timelineItem.executionTimeMs,
                docqlStats = timelineItem.docqlStats,
                onOpenFileViewer = onOpenFileViewer,
                onExpand = onExpand
            )
        }

        is TimelineItem.ErrorItem -> {
            ToolErrorItem(error = timelineItem.message, onDismiss = { renderer.clearError() })
        }

        is TimelineItem.TaskCompleteItem -> {
            TaskCompletedItem(
                success = timelineItem.success,
                message = timelineItem.message
            )
        }

        is TimelineItem.TerminalOutputItem -> {
            TerminalOutputItem(
                command = timelineItem.command,
                output = timelineItem.output,
                exitCode = timelineItem.exitCode,
                executionTimeMs = timelineItem.executionTimeMs,
                onExpand = onExpand
            )
        }

        is TimelineItem.LiveTerminalItem -> {
            LiveTerminalItem(
                sessionId = timelineItem.sessionId,
                command = timelineItem.command,
                workingDirectory = timelineItem.workingDirectory,
                ptyHandle = timelineItem.ptyHandle,
                exitCode = timelineItem.exitCode,
                executionTimeMs = timelineItem.executionTimeMs,
                output = timelineItem.output
            )
        }

        is TimelineItem.AgentSketchBlockItem -> {
            AgentSketchBlockItem(
                agentName = timelineItem.agentName,
                language = timelineItem.language,
                code = timelineItem.code,
                metadata = timelineItem.metadata
            )
        }
    }
}

/**
 * Platform-specific live terminal display.
 * On JVM with PTY support: Renders an interactive terminal widget
 * On other platforms: Shows a message that live terminal is not available
 *
 * @param exitCode Exit code when completed (null if still running)
 * @param executionTimeMs Execution time when completed (null if still running)
 * @param output Captured output when completed (null if still running or not captured)
 */
@Composable
expect fun LiveTerminalItem(
    sessionId: String,
    command: String,
    workingDirectory: String?,
    ptyHandle: Any?,
    exitCode: Int? = null,
    executionTimeMs: Long? = null,
    output: String? = null
)

@Composable
fun MessageItem(
    message: Message,
    tokenInfo: cc.unitmesh.llm.compression.TokenInfo? = null
) {
    val isUser = message.role == MessageRole.USER

    Row(
        modifier = Modifier.fillMaxWidth(),
        horizontalArrangement = if (isUser) Arrangement.End else Arrangement.Start
    ) {
        Surface(
            modifier = Modifier.fillMaxWidth(),
            shape = RoundedCornerShape(4.dp),
            color = MaterialTheme.colorScheme.surface
        ) {
            PlatformMessageTextContainer(text = message.content) {
                Column(modifier = Modifier.padding(8.dp)) {
                    if (!isUser) {
                        SketchRenderer.RenderResponse(
                            content = message.content,
                            isComplete = true,
                            modifier = Modifier.fillMaxWidth()
                        )
                    } else {
                        Text(
                            text = message.content,
                            fontFamily = getUtf8FontFamily(),
                            style = MaterialTheme.typography.bodyMedium
                        )
                    }

                    if (!isUser && tokenInfo != null && tokenInfo.totalTokens > 0) {
                        Spacer(modifier = Modifier.height(4.dp))
                        Text(
                            text = "${tokenInfo.inputTokens} + ${tokenInfo.outputTokens} (${tokenInfo.totalTokens} tokens)",
                            style = MaterialTheme.typography.labelSmall,
                            color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
                            fontFamily = FontFamily.Monospace
                        )
                    }
                }
            }
        }
    }
}

@Composable
expect fun PlatformMessageTextContainer(
    text: String,
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
)

@Composable
fun StreamingMessageItem(
    content: String,
    onContentUpdate: (blockCount: Int) -> Unit = {}
) {
    Surface(
        color = MaterialTheme.colorScheme.surfaceVariant,
        shape = RoundedCornerShape(4.dp)
    ) {
        Column(modifier = Modifier.padding(12.dp)) {
            if (content.isNotEmpty()) {
                Spacer(modifier = Modifier.height(8.dp))
                // Use SketchRenderer to support thinking blocks in streaming content
                // Pass onContentUpdate to trigger scroll when new blocks are rendered
                SketchRenderer.RenderResponse(
                    content = content,
                    isComplete = false,
                    onContentUpdate = onContentUpdate,
                    modifier = Modifier.fillMaxWidth()
                )
            }
        }
    }
}

@Composable
fun TaskCompletedItem(
    success: Boolean,
    message: String
) {
    Surface(
        color = MaterialTheme.colorScheme.primaryContainer,
        shape = RoundedCornerShape(8.dp)
    ) {
        Row(
            modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp),
            verticalAlignment = Alignment.CenterVertically,
            horizontalArrangement = Arrangement.spacedBy(8.dp)
        ) {
            if (success) {
                Text(
                    text = "completed",
                    color = MaterialTheme.colorScheme.onPrimaryContainer.copy(alpha = 0.3f),
                    fontSize = 10.sp
                )
            } else {
                Icon(
                    imageVector = AutoDevComposeIcons.Warning,
                    contentDescription = "Warning",
                    tint = MaterialTheme.colorScheme.error,
                    modifier = Modifier.size(16.dp)
                )
            }

            Text(
                text = message,
                color = MaterialTheme.colorScheme.onPrimaryContainer,
                fontWeight = FontWeight.Medium,
                fontSize = 10.sp
            )
        }
    }
}

/**
 * NanoDSL Timeline Item - displays generated NanoDSL code
 * @param irJson The IR JSON representation (reserved for future preview feature)
 */
@Composable
fun NanoDSLTimelineItem(
    source: String,
    @Suppress("unused") irJson: String?, // Reserved for future live preview feature
    componentName: String?,
    generationAttempts: Int,
    isValid: Boolean,
    warnings: List<String>,
    modifier: Modifier = Modifier
) {
    // TODO: Add live preview toggle when NanoRenderer integration is ready
    // var showPreview by remember { mutableStateOf(false) }

    Surface(
        modifier = modifier.fillMaxWidth().padding(horizontal = 8.dp, vertical = 4.dp),
        shape = RoundedCornerShape(8.dp),
        color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f)
    ) {
        Column(
            modifier = Modifier.padding(12.dp)
        ) {
            // Header row with component name and status
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.CenterVertically
            ) {
                Row(
                    verticalAlignment = Alignment.CenterVertically,
                    horizontalArrangement = Arrangement.spacedBy(8.dp)
                ) {
                    Text(
                        text = "🎨",
                        fontSize = 16.sp
                    )
                    Text(
                        text = componentName ?: "Generated UI",
                        color = MaterialTheme.colorScheme.onSurface,
                        fontWeight = FontWeight.SemiBold,
                        fontSize = 14.sp
                    )
                    if (generationAttempts > 1) {
                        Surface(
                            shape = RoundedCornerShape(4.dp),
                            color = MaterialTheme.colorScheme.tertiary.copy(alpha = 0.2f)
                        ) {
                            Text(
                                text = "$generationAttempts attempts",
                                modifier = Modifier.padding(horizontal = 6.dp, vertical = 2.dp),
                                fontSize = 10.sp,
                                color = MaterialTheme.colorScheme.tertiary
                            )
                        }
                    }
                }

                // Validity indicator
                Text(
                    text = if (isValid) "✅ Valid" else "⚠️ Invalid",
                    fontSize = 12.sp,
                    color = if (isValid) MaterialTheme.colorScheme.primary
                            else MaterialTheme.colorScheme.error
                )
            }

            // Warnings
            if (warnings.isNotEmpty()) {
                Spacer(modifier = Modifier.height(4.dp))
                warnings.forEach { warning ->
                    Text(
                        text = "⚠ $warning",
                        fontSize = 11.sp,
                        color = MaterialTheme.colorScheme.error.copy(alpha = 0.8f)
                    )
                }
            }

            Spacer(modifier = Modifier.height(8.dp))

            // Code display
            val lines = source.lines()
            val maxLineNumWidth = lines.size.toString().length

            Surface(
                modifier = Modifier.fillMaxWidth(),
                shape = RoundedCornerShape(4.dp),
                color = MaterialTheme.colorScheme.surface
            ) {
                Column(modifier = Modifier.padding(8.dp)) {
                    // Line numbers and code
                    lines.forEachIndexed { index, line ->
                        Row(modifier = Modifier.fillMaxWidth()) {
                            Text(
                                text = (index + 1).toString().padStart(maxLineNumWidth, ' '),
                                color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.4f),
                                fontFamily = FontFamily.Monospace,
                                fontSize = 11.sp,
                                modifier = Modifier.padding(end = 8.dp)
                            )
                            Text(
                                text = line,
                                color = MaterialTheme.colorScheme.onSurface,
                                fontFamily = FontFamily.Monospace,
                                fontSize = 11.sp
                            )
                        }
                    }
                }
            }

            // Footer with line count
            Spacer(modifier = Modifier.height(4.dp))
            Text(
                text = "${lines.size} lines of NanoDSL code",
                fontSize = 10.sp,
                color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.5f)
            )
        }
    }
}

/**
 * Composable for rendering Agent-generated sketch blocks (chart, nanodsl, mermaid, etc.)
 * Uses SketchRenderer to handle all code block types uniformly.
 */
@Composable
fun AgentSketchBlockItem(
    agentName: String,
    language: String,
    code: String,
    metadata: Map<String, String> = emptyMap()
) {
    // Construct code fence format for SketchRenderer to parse
    val fencedContent = "```$language\n$code\n```"

    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(vertical = 4.dp),
        colors = CardDefaults.cardColors(
            containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f)
        ),
        shape = RoundedCornerShape(8.dp)
    ) {
        Column(
            modifier = Modifier.padding(12.dp)
        ) {
            // Header with agent name and language
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.CenterVertically
            ) {
                Row(
                    verticalAlignment = Alignment.CenterVertically,
                    horizontalArrangement = Arrangement.spacedBy(8.dp)
                ) {
                    Text(
                        text = "📊",
                        fontSize = 14.sp
                    )
                    Text(
                        text = agentName,
                        fontWeight = FontWeight.Medium,
                        fontSize = 12.sp,
                        color = MaterialTheme.colorScheme.primary
                    )
                }
                Text(
                    text = language,
                    fontSize = 10.sp,
                    color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f),
                    fontFamily = FontFamily.Monospace
                )
            }

            Spacer(modifier = Modifier.height(8.dp))

            // Use SketchRenderer to render the content uniformly
            SketchRenderer.Render(
                content = fencedContent,
                isComplete = true,
                modifier = Modifier.fillMaxWidth()
            )
        }
    }
}

